//
// Created by Never on 2019/10/12.
//

#include <gtest/gtest.h>
#define protected public
#include "../SRC/MinimalSpanningForest.h"

class TestMinimalSpanningTree: public testing::Test{
public:
    std::vector<int> roots = {0};
    std::vector<int> nodes = {1, 2, 3, 4, 5, 6};
    std::vector<int> usedRoots = {0};
    std::vector<std::vector<int>> distances = {{0, 2, 4, 1, unConnected, unConnected, unConnected},
                                               {2, 0, unConnected, 3, 10, unConnected, unConnected},
                                               {4, unConnected, 0, 2, unConnected, 5, unConnected},
                                               {1, 3, 2, 0, 7, 8, 4},
                                               {unConnected, 10, unConnected, 7, 0, unConnected, 6},
                                               {unConnected, unConnected, 5, 8, unConnected, 0, 1},
                                               {unConnected, unConnected, unConnected, 4, 6, 1, 0}};
    int expectedCostOfMSF = 16;
    MinimalSpanningForest<int> minimalSpanningForest;
    TestMinimalSpanningTree():minimalSpanningForest(roots, nodes, distances)
    {}
    void testInitialTable(){
        std::vector<bool> expectedIsKnown = {true, false, false, false, false, false, false};
        std::vector<int> expectedPrevious = {0, 0, 0, 0, 0, 0, 0};
        std::vector<int> expectedMinCost = {0, 2, 4, 1, INT32_MAX, INT32_MAX, INT32_MAX};
        ASSERT_EQ(expectedIsKnown, minimalSpanningForest.isKnown);
        ASSERT_EQ(expectedMinCost, minimalSpanningForest.minCost);
        ASSERT_EQ(expectedPrevious, minimalSpanningForest.preNode);
    }
};

class TestMinimalSpanningForest: public testing::Test{
public:
    // this instance is presented in instance_for_msf.png
    std::vector<int> roots = {0, 2, 5};
    std::vector<int> nodes = {1, 3, 4, 6, 7};
    std::vector<int> usedRoots = {0, 2, 5};
    std::vector<int> usedPartialRoots = {0, 2};
    std::vector<std::vector<int>> distances = {{0, 1, unConnected, unConnected, 1, unConnected, unConnected, 1},
                                               {1, 0, unConnected, unConnected, unConnected, unConnected, unConnected, unConnected},
                                               {unConnected, unConnected, 0, 1, unConnected, unConnected, unConnected, unConnected},
                                               {unConnected, unConnected, 1, 0, unConnected, unConnected, unConnected, unConnected},
                                               {1, unConnected, unConnected, unConnected, 0, unConnected, unConnected, unConnected},
                                               {unConnected, unConnected, unConnected, unConnected, unConnected, 0, 1, unConnected},
                                               {unConnected, unConnected, unConnected, unConnected, unConnected, 1, 0, unConnected},
                                               {1, unConnected, unConnected, unConnected, unConnected, unConnected, unConnected, 0}};
    int expectedCostOfMSF = 5;
    int expectedCostOfPartialMSF = 4;
    MinimalSpanningForest<int> minimalSpanningForest;
    TestMinimalSpanningForest():minimalSpanningForest(roots, nodes, distances)
    {}
    void checkInitialTable(std::vector<bool> expectedIsKnown, std::vector<int> expectedPrevious,
                           std::vector<int> expectedMinCost)
    {
        ASSERT_EQ(expectedIsKnown, minimalSpanningForest.isKnown);
        ASSERT_EQ(expectedMinCost, minimalSpanningForest.minCost);
        ASSERT_EQ(expectedPrevious, minimalSpanningForest.preNode);
    }
    void testInitialTableForAllRoots(){
        std::vector<bool> expectedIsKnown = {true, false, true, false, false, true, false, false};
        std::vector<int> expectedPrevious = {0, 0, 2, 2, 0, 5, 5, 0};
        std::vector<int> expectedMinCost = {0, 1, 0, 1, 1, 0, 1, 1};
        checkInitialTable(expectedIsKnown, expectedPrevious, expectedMinCost);
    }
    void testInitialTableForPartialRoots(){
        std::vector<bool> expectedIsKnown = {true, false, true, false, false, false, false, false};
        std::vector<int> expectedPrevious = {0, 0, 2, 2, 0, 0, 0, 0};
        std::vector<int> expectedMinCost = {0, 1, 0, 1, 1, INT32_MAX, INT32_MAX, 1};
        checkInitialTable(expectedIsKnown, expectedPrevious, expectedMinCost);
    }
};

TEST_F(TestMinimalSpanningTree, InitialTable)
{
    minimalSpanningForest.initialTable(usedRoots);

    testInitialTable();
}
TEST_F(TestMinimalSpanningTree, GenerateMinimalSpanningTree)
{
    auto cost = minimalSpanningForest.minimalSpanningForest(usedRoots);

    ASSERT_EQ(expectedCostOfMSF, cost);
}
TEST_F(TestMinimalSpanningForest, InitialTable)
{
    minimalSpanningForest.initialTable(usedRoots);

    testInitialTableForAllRoots();
}
TEST_F(TestMinimalSpanningForest, GenerateMinimalSpanningForest)
{
    auto cost = minimalSpanningForest.minimalSpanningForest(usedRoots);

    ASSERT_EQ(expectedCostOfMSF, cost);
}
TEST_F(TestMinimalSpanningForest, InitialTableForPartialRoots)
{
    minimalSpanningForest.initialTable(usedPartialRoots);

    testInitialTableForPartialRoots();
}
TEST_F(TestMinimalSpanningForest, GenerateMinimalSpanningForestForPartialRoots)
{
    auto cost = minimalSpanningForest.minimalSpanningForest(usedPartialRoots);

    ASSERT_EQ(expectedCostOfPartialMSF, cost);
}
TEST_F(TestMinimalSpanningForest, MultiRun)
{
    auto cost = minimalSpanningForest.minimalSpanningForest(usedPartialRoots);

    ASSERT_EQ(expectedCostOfPartialMSF, cost);

    cost = minimalSpanningForest.minimalSpanningForest(usedRoots);

    ASSERT_EQ(expectedCostOfMSF, cost);
}
GTEST_API_ int main(int argc, char** argv) {
    testing::InitGoogleTest(&argc, argv);
    return RUN_ALL_TESTS();
}